/***************************************************************************
   Filename:    boxgen.cpp
   Author:      Josh Partridge
   Description: Contains methods for drawing boxes
****************************************************************************/
#include "boxgen.h"

using namespace std;

/************************************************************************************
Name:               horizFill
Description:        draws various boxes filled in with horizontal lines
Input:
             brush: reference to a Brush
                 x: int representing x position of left side
                 y: int representing y position of top side
             width: int representing width of the box
            height: int representing height of the box
             lines: int representing horizontal lines per character
              wavy: bool representing of wavy characters should be used
 *************************************************************************************/
void horizFill(Brush& brush, int x, int y, int width, int height, int lines, bool wavy)
{
    for(int y_pos=y; y_pos<y+height; y_pos++)
    {
        for(int x_pos=x; x_pos<x+width; x_pos++)
        {
            if(!wavy)
            {
                switch(lines)
                {
                    case 1: brush.plot(x_pos, y_pos, SHORIZ);break;
                    case 2: brush.plot(x_pos, y_pos, DHORIZ);break;
                    case 3: brush.plot(x_pos, y_pos, THORIZ);break;
                    case 4: brush.plot(x_pos, y_pos, SOLIDLOW);break;
                    default: brush.plot(x_pos, y_pos, FSINGLEHORIZ);break;
                }
            }
            else
            {
                switch(lines)
                {
                    case 1: brush.plot(x_pos, y_pos, SHORIZWAVY);break;
                    default: brush.plot(x_pos, y_pos, DHORIZWAVY);break;
                }
            }
        }
    }
}

/************************************************************************************
Name:               verticalFill
Description:        draws various boxes filled in with vertical lines
Input:
             brush: reference to a Brush
                 x: int representing x position of left side
                 y: int representing y position of top side
             width: int representing width of the box
            height: int representing height of the box
             lines: int representing vertical lines per character
              wavy: bool representing of wavy characters should be used
 *************************************************************************************/
void verticalFill(Brush& brush, int x, int y, int width, int height, int lines, bool wavy)
{
    for(int y_pos=y; y_pos<y+height; y_pos++)
    {
        for(int x_pos=x; x_pos<x+width; x_pos++)
        {
            if(!wavy)
            {
                switch(lines)
                {
                    case 1: brush.plot(x_pos, y_pos, SVERT);break;
                    case 2: brush.plot(x_pos, y_pos, SOLIDLEFT);break;
                    default: brush.plot(x_pos, y_pos, DVERT);break;
                }
            }
            else if(y_pos%2==0)
            {
                switch(lines)
                {
                    case 1: brush.plot(x_pos, y_pos, ')');break;
                    case 2: brush.plot(x_pos, y_pos, DARROWRIGHT);break;
                    default: brush.plot(x_pos, y_pos, FVERTWAVY);
                }
            }
            else
            {
                switch(lines)
                {
                    case 1: brush.plot(x_pos, y_pos, '(');break;
                    case 2: brush.plot(x_pos, y_pos, DARROWLEFT);break;
                    default: brush.plot(x_pos, y_pos, FVERTWAVY);
                }
            }
        }
    }
}

/************************************************************************************
Name:               fancyFill
Description:        draws various boxes filled in
Input:
             brush: reference to a Brush
                 x: int representing x position of left side
                 y: int representing y position of top side
             width: int representing width of the box
            height: int representing height of the box
             lines: int representing lines per character
           density: int representing of density of solid fills
 *************************************************************************************/
void fancyFill(Brush& brush, int x, int y, int width, int height, int lines, int density)
{
    for(int y_pos=y; y_pos<y+height; y_pos++)
    {
        for(int x_pos=x; x_pos<x+width; x_pos++)
        {
            if(!density)
            {
                switch(lines)
                {
                    case 1: brush.plot(x_pos, y_pos, SHORIZINTSVERT);break;
                    case 2: brush.plot(x_pos, y_pos, DHORIZINTDVERT);break;
                    default: brush.plot(x_pos, y_pos, FSINGLEHORIZ);break;
                }
            }
            else
            {
                switch(density)
                {
                    case 1: brush.plot(x_pos, y_pos, LOWDENSE);break;
                    case 2: brush.plot(x_pos, y_pos, MEDDENSE);break;
                    case 3: brush.plot(x_pos, y_pos, HIGHDENSE);break;
                    default: brush.plot(x_pos, y_pos, SOLID);
                }
            }
        }
    }
}

/************************************************************************************
Name:               fancyBox
Description:        draws various fancy box outlines
Input:
             brush: reference to a Brush
                 x: int representing x position of left side
                 y: int representing y position of top side
             width: int representing width of the box
            height: int representing height of the box
              wavy: bool representing of wavy characters should be used
           extreme: bool representing "extreme" mode (different characters)
 *************************************************************************************/
void fancyBox(Brush& brush, int x, int y, int width, int height, bool wavy, bool extreme)
{
    if(width==1 && height==1)
        brush.plot(x,y,SSINGLE);
    else if(width<2 || height<2)
        return;

    if(!wavy && !extreme)
    {
        brush.plot(x, y, FTOPLEFT);
        brush.plot(x+width, y, STOPRIGHT);
        brush.plot(x, y+height, SBOTTOMLEFT);
        brush.plot(x+width, y+height, FBOTTOMRIGHT);
    }
    int i=x;
    for (i=x+1; i<x+width; i++)
    {
        if(!wavy && !extreme)
        {
            brush.plot(i, y, SHORIZ);
            brush.plot(i, y+height, SHORIZ);
        }
        else if(!extreme && wavy)
        {
            brush.plot(i, y, SHORIZWAVY);
            brush.plot(i, y+height, SHORIZWAVY);
        }
        else if(extreme && wavy)
        {
            if(i%2==0)
            {
                brush.plot(i, y, 'U');
                brush.plot(i, y+height, STOPLOOP);
            }
            else
            {
                brush.plot(i, y, STOPLOOP);
                brush.plot(i, y+height, 'U');
            }
        }
        else
        {
            if(i%2==0)
            {
                brush.plot(i, y, SQRT);
                brush.plot(i, y+height, '^');
            }
            else
            {
                brush.plot(i, y, '^');
                brush.plot(i, y+height, SQRT);
            }
        }
    }
    for (i=y+1; i<y+height; i++)
    {
        if(!wavy && !extreme)
        {
            brush.plot(x, i, SVERT);
            brush.plot(x+width, i, SVERT);
        }
        else if(i%2==0)
        {
            if(wavy)
            {
                brush.plot(x, i, '(');
                brush.plot(x+width, i, ')');
            }
            else
            {
                brush.plot(x, i, '<');
                brush.plot(x+width, i, '>');
            }
        }
        else
        {
            if(wavy)
            {
                brush.plot(x, i, ')');
                brush.plot(x+width, i, '(');
            }
            else
            {
                brush.plot(x, i, '>');
                brush.plot(x+width, i, '<');
            }
        }
    }
    brush.plot(0,y+width+1,  32);
}

/************************************************************************************
Name:               doubleFancyBox
Description:        draws various double line fancy box outlines
Input:
             brush: reference to a Brush
                 x: int representing x position of left side
                 y: int representing y position of top side
             width: int representing width of the box
            height: int representing height of the box
              wavy: bool representing of wavy characters should be used
 *************************************************************************************/
void doubleFancyBox(Brush& brush, int x, int y, int width, int height, bool wavy)
{
    if(width==1 && height==1)
        brush.plot(x,y,SSINGLE);
    else if(width<2 || height<2)
        return;

    int i=x;
    for (i=x+1; i<x+width; i++)
    {
        if(wavy)
        {
            brush.plot(i, y, DHORIZWAVY);
            brush.plot(i, y+height, DHORIZWAVY);
        }else
        {
            brush.plot(i, y, DARROWRIGHT);
            brush.plot(i, y+height, DARROWLEFT);
        }
    }
    for (i=y+1; i<y+height; i++)
    {
        if(i%2==0)
        {
            brush.plot(x, i, DARROWLEFT);
            brush.plot(x+width, i, DARROWRIGHT);
        }
        else
        {
            brush.plot(x, i, DARROWRIGHT);
            brush.plot(x+width, i, DARROWLEFT);
        }
    }
    brush.plot(0,y+width+1,  32);
}

/************************************************************************************
Name:               singleLineBox
Description:        draws a single line width box outline
Input:
             brush: reference to a Brush
                 x: int representing x position of left side
                 y: int representing y position of top side
             width: int representing width of the box
            height: int representing height of the box
 *************************************************************************************/
void singleLineBox(Brush& brush, int x, int y, int width, int height)
{
    int i=x;
    if(width==0 && height==0)
    {
        brush.plot(x,y, SSINGLE);
        return;
    }
    else if(width==0 && height>0)
    {
        brush.plot(x,y, STOPLOOP);
        for(i=y+1; i<y+height; i++)
        {
            brush.plot(x,i, DVERT);
        }
        brush.plot(x,y+height, SBOTTOMLOOP);
        return;
    }
    else if(height==0 && width>0)
    {
        brush.plot(x,y, STOPLOOP);
        for(i=y+1; i<y+height; i++)
        {
            brush.plot(x,i, DVERT);
        }
        brush.plot(x+width,y, SBOTTOMLOOP);
        return;
    }
    else if(width<0 || height<0)
        return;

    brush.plot(x, y, STOPLEFT);
    brush.plot(x+width, y, STOPRIGHT);
    brush.plot(x, y+height, SBOTTOMLEFT);
    brush.plot(x+width, y+height, SBOTTOMRIGHT);

    for (i=x+1; i<x+width; i++)
    {
        brush.plot(i, y,  SHORIZ);
        brush.plot(i, y+height, SHORIZ);
    }
    for (i=y+1; i<y+height; i++)
    {
        brush.plot(x, i,  SVERT);
        brush.plot(x+width, i, SVERT);
    }
    brush.plot(0,y+width+1,  32);
}

/************************************************************************************
Name:               singleLineBox (overloaded)
Description:        draws a single line width box outline
Input:
             brush: reference to a Brush
                tl: COORD representing top left coordinates
                br: COORD representing bottom right coordinates
*************************************************************************************/
void singleLineBox(Brush& brush, COORD tl, COORD br)
{
    singleLineBox(brush, tl.X, tl.Y, br.X - tl.X, br.Y - tl.Y);
}

/************************************************************************************
Name:               doubleLineBox
Description:        draws a double line width box outline
Input:
             brush: reference to a Brush
                 x: int representing x position of left side
                 y: int representing y position of top side
             width: int representing width of the box
            height: int representing height of the box
 *************************************************************************************/
void doubleLineBox(Brush& brush, int x, int y, int width, int height){
    brush.plot(x, y, DTOPLEFT);
    brush.plot(x+width, y, DTOPRIGHT);
    brush.plot(x, y+height, DBOTTOMLEFT);
    brush.plot(x+width, y+height, DBOTTOMRIGHT);

    int i=x;
    for (i=x+1; i<x+width; i++)
    {
        brush.plot(i, y, DHORIZ);
        brush.plot(i, y+height, DHORIZ);
    }
    for (i=y+1; i<y+height; i++)
    {
        brush.plot(x, i, DVERT);
        brush.plot(x+width, i, DVERT);
    }
    brush.plot(0,y+width+1, (unsigned char)32);
}

/************************************************************************************
Name:               doubleLineBox (overloaded)
Description:        draws a double line width box outline
Input:
             brush: reference to a Brush
                tl: COORD representing top left coordinates
                br: COORD representing bottom right coordinates
*************************************************************************************/
void doubleLineBox(Brush& brush, COORD tl, COORD br){
    doubleLineBox(brush, tl.X, tl.Y, br.X - tl.X, br.Y - tl.Y);
}
